package com.auto.api.core.entity;

import com.auto.api.core.constants.MappingConstants;
import java.beans.PropertyDescriptor;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import lombok.Data;
import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.core.ResolvableType;
import org.springframework.util.ReflectionUtils;

/**
 * @program:
 * @description:
 * @author: liangshf
 * @create: 2020-10-30
 */
@Data
public class ParseTypeContext<R> {

    /**
     * 结果数据
     */
    private R result;

    /**
     * Class目标类型
     */
    private Class clazz;

    /**
     * 类型对应父属性全路径
     */
    private String parentPropertyName;

    /**
     * class SimpleName
     */
    private String simpleClassName;


    /**
     * Class目标类型对象属性集合
     */
    private List<PropertyDescriptor> props;

    /**
     * 封装了所有泛型信息的类型
     */
    private ResolvableType resolvableType;

    public ParseTypeContext() {

    }

    public ParseTypeContext(Class clazz) {
        this.clazz = clazz;
        this.simpleClassName = clazz.getSimpleName();
        resolvableType = ResolvableType.forClass(clazz);
        this.parentPropertyName = MappingConstants.EMPTY_STRING;
        setProps(filterBuildProps(getClazz()));
    }

    public ParseTypeContext(ResolvableType resolvableType) {
        if (resolvableType.resolve() == null) {
            this.clazz = MappingConstants.INT.getClass();
        } else {
            this.clazz = resolvableType.resolve();
        }

        this.simpleClassName = clazz.getSimpleName();
        this.resolvableType = resolvableType;
        this.parentPropertyName = MappingConstants.EMPTY_STRING;
        setProps(filterBuildProps(getClazz()));
    }

    public ParseTypeContext(ResolvableType resolvableType, String parentPropertyName) {
        if (resolvableType.resolve() == null) {
            this.clazz = MappingConstants.INT.getClass();
        } else {
            this.clazz = resolvableType.resolve();
        }
        this.resolvableType = resolvableType;
        this.simpleClassName = clazz.getSimpleName();
        this.parentPropertyName = parentPropertyName;
        setProps(filterBuildProps(getClazz()));
    }

    protected List<PropertyDescriptor> filterBuildProps(Class clazz) {
        PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(clazz);
        if (descriptors == null) {
            return Collections.emptyList();
        }
        return Arrays.asList(descriptors).stream()
                .filter(prop -> !(MappingConstants.CLASS.equals(prop.getName())
                        || (prop.getReadMethod() == null && prop.getWriteMethod() == null))
                    && ReflectionUtils.findField(clazz, prop.getName()) != null).collect(Collectors.toList());
    }
}